#include "Prerequisites.h"
#include "Frustum.h"


Frustum::Frustum()
{
	m_fov = PI / 4.f;	// default field of view is 90 degrees
	m_aspect = 1.f;		// default aspect ratio is 1:1
	m_near = 1.f;		// default near clip plane is 1m away from the camera
	m_far = 1000.f;		// default near clip plane is 100m away from the camera
}

bool Frustum::Inside(const Vector3 &Vector2) const
{
	for (int i=0; i<NumPlanes; ++i)
	{
		if (!mp_lanes[i].Inside(Vector2))
			return false;
	}

	return true;
}

bool Frustum::Inside(const Vector3 &Vector2, const float radius) const
{
	for(int i = 0; i < NumPlanes; ++i) 
	{	
		if (!mp_lanes[i].Inside(Vector2, radius))
			return false;
	}	

	// otherwise we are fully in view
	return(true);
}

void Frustum::Init(const float fov, const float aspect, const float nearClip, const float farClip)
{
	m_fov = fov;
	m_aspect = aspect;
	m_near = nearClip;
	m_far = farClip;

	float tanFovOver2 = (float)tan(m_fov / 2.f);
	Vector3 nearRight = (m_near * tanFovOver2) * m_aspect * g_right;
	Vector3 farRight = (m_far * tanFovOver2) * m_aspect * g_right;
	Vector3 nearUp = (m_near * tanFovOver2 ) * g_up;
	Vector3 farUp = (m_far * tanFovOver2)  * g_up;

	// Points start in the upper right and go around clockwise
	m_nearClip[0] = (m_near * g_forward) - nearRight + nearUp;
	m_nearClip[1] = (m_near * g_forward) + nearRight + nearUp;
	m_nearClip[2] = (m_near * g_forward) + nearRight - nearUp;
	m_nearClip[3] = (m_near * g_forward) - nearRight - nearUp;

	m_farClip[0] = (m_far * g_forward) - farRight + farUp;
	m_farClip[1] = (m_far * g_forward) + farRight + farUp;
	m_farClip[2] = (m_far * g_forward) + farRight - farUp;
	m_farClip[3] = (m_far * g_forward) - farRight - farUp;

	// now we have all eight points. Time to construct 6 planes.
	// the normals point away from you if you use counter clockwise verts.

	Vector3 origin(0.f, 0.f, 0.f);
	mp_lanes[Near].Init(m_nearClip[2], m_nearClip[1], m_nearClip[0]);
	mp_lanes[Far].Init(m_farClip[0], m_farClip[1], m_farClip[2]);
	mp_lanes[Right].Init(m_farClip[2], m_farClip[1], origin);
	mp_lanes[Top].Init(m_farClip[1], m_farClip[0], origin);
	mp_lanes[Left].Init(m_farClip[0], m_farClip[3], origin);
	mp_lanes[Bottom].Init(m_farClip[3], m_farClip[2], origin);
}

void Frustum::Render()
{
	D3D9Vertex_Colored verts[24];
	for(int i = 0; i < 8; ++i)
	{
		verts[i].color = g_white;
	}

	for(int i = 0; i < 8; ++i)
	{
		verts[i+8].color = g_red;
	}

	for(int i = 0; i < 8; ++i)
	{
		verts[i+16].color = g_blue;
	}

	// Draw the near clip plane
	verts[0].position = m_nearClip[0];	verts[1].position = m_nearClip[1];
	verts[2].position = m_nearClip[1];	verts[3].position = m_nearClip[2];
	verts[4].position = m_nearClip[2];	verts[5].position = m_nearClip[3];
	verts[6].position = m_nearClip[3];	verts[7].position = m_nearClip[0];

	// Draw the far clip plane
	verts[8].position = m_farClip[0];	verts[9].position = m_farClip[1];
	verts[10].position = m_farClip[1];	verts[11].position = m_farClip[2];
	verts[12].position = m_farClip[2];	verts[13].position = m_farClip[3];
	verts[14].position = m_farClip[3];	verts[15].position = m_farClip[0];

	// Draw the edges between the near and far clip plane
	verts[16].position = m_nearClip[0];	verts[17].position = m_farClip[0];
	verts[18].position = m_nearClip[1];	verts[19].position = m_farClip[1];
	verts[20].position = m_nearClip[2];	verts[21].position = m_farClip[2];
	verts[22].position = m_nearClip[3];	verts[23].position = m_farClip[3];

	DWORD oldLightMode;
	DXUTGetD3D9Device()->GetRenderState(D3DRS_LIGHTING, &oldLightMode);
	DXUTGetD3D9Device()->SetRenderState(D3DRS_LIGHTING, FALSE);

	DXUTGetD3D9Device()->SetFVF(D3D9Vertex_Colored::FVF);
	DXUTGetD3D9Device()->DrawPrimitiveUP(D3DPT_LINELIST, 12, verts, sizeof(D3D9Vertex_Colored));

	DXUTGetD3D9Device()->SetRenderState(D3DRS_LIGHTING, oldLightMode);
}